import {addEventListener,removeEventListener,preventDefault}from 'public/util/passiveEventListener';

export const calcAngle=function(point1,point2){
    //下拉的角度是否在配置的范围内
    const x = Math.abs(point1.x - point2.x);
    const y = Math.abs(point1.y - point2.y);
    const z = Math.sqrt(x * x + y * y);
    return Math.asin(y / z) / Math.PI * 180;//两点之间的角度,区间 [0,90]
};

export const getTouchPoint=(e)=>{
    return {
        x: e.touches[0].pageX,
        y: e.touches[0].pageY
    }
};
export const downState={
    end:0,
    starting:1,
    moving:2,
};
const resetData=function(data={}){
    return {
        state:downState.end,
        point:null,//当前点
        startPoint:null,//开始点
        lastPoint:null,//结束点
        diffStartY:0,//距离开始点Y偏移
        diffLastY:0,//距离lastPoint点Y偏移
        height:0,//当前下拉的高度
        ...data
    };
};
const setConfig=function(config={}){
    return {
        minAngle:45,
        onDown(){
        },
        onDownEnd(){
        },
        onDownStart(){
        },
        enableDown(){
            return true;
        },
        ...config
    };
};
export class DownRefresh{
    data=resetData();
    resetData(data){
        this.data=resetData(data);
    }
    constructor(dom,config){
        this.dom=dom;
        this.config=setConfig(config);
        this.bindEvents();
    }
    isTop(){
        return this.dom.scrollTop<=1;
    }
    isDown(point){
        return (point.y-this.data.lastPoint.y)>0;
    }
    touchStart=(e)=>{
        if(!this.isTop()){
            return false;
        }
        const point=getTouchPoint(e);
        this.resetData({
            startPoint:point,
            lastPoint:point,
            state:downState.starting
        });
        this.bindMove();
    };
    initTouchMove(e,point){
        const {state}=this.data;
        if((state!==downState.starting)||
            (!this.checkAngle(point))||
            (!this.isDown(point))||
            (!this.config.enableDown(this.data))
        ){
            this.data.state=downState.end;
            this.unbindMove();
            return false;
        }
        this.config.onDownStart(this.data);
        this.data.state=downState.moving;
        this._touchMove(e,point);
    };
    _touchMove(e,point){
        const {startPoint,lastPoint}=this.data;
        const diffStartY=point.y-startPoint.y;
        const diffLastY=point.y-lastPoint.y;
        const {height}=this.calcDownHeight(diffStartY,diffLastY);

        const data=this.data;
        data.diffStartY=diffStartY;
        data.diffLastY=diffLastY;
        data.height=height;
        data.diffLastY=diffLastY;

        this.config.onDown(this.data);
        preventDefault(e);
    }
    touchMove=(e)=>{
        const point=getTouchPoint(e);
        const data=this.data;
        data.point=point;
        if(data.state!==downState.moving){
            this.initTouchMove(e,point);
        }else{
            this._touchMove(e,point);
        }
        data.lastPoint=point;
    };
    touchEnd=()=>{
        if(this.data.state===downState.end){
            return;
        }
        this.cancelDown();
    };
    cancelDown(){
        this.config.onDownEnd();
        this.resetData();
    }
    calcDownHeight(diffStartY,diffLastY){
        const {outOffsetRate,offset}=this.config;
        const diffHeight=(diffStartY>=offset)?diffLastY*outOffsetRate:diffLastY;
        return {
            height:diffStartY+diffHeight,
            diffHeight
        }
    }
    checkAngle(point){
        const {lastPoint}=this.data;
        const angle=calcAngle(lastPoint,point);
        return angle>this.config.minAngle;
    }
    bindMove(){
        this.dom.addEventListener('touchmove',this.touchMove);
    }
    unbindMove(){
        this.dom.removeEventListener('touchmove',this.touchMove);
    }
    bindEvents(){
        const dom=this.dom;
        this.unbindEvents();
        /*        dom.addEventListener('touchstart',this.touchStart,{
                    passive:true
                });*/
        addEventListener(dom,'touchstart',this.touchStart);
        addEventListener(dom,'touchend',this.touchEnd);
        addEventListener(dom,'touchcancel',this.touchEnd);
    }
    unbindEvents(){
        const dom=this.dom;
        removeEventListener(dom,'touchstart',this.touchStart);
        removeEventListener(dom,'touchend',this.touchEnd);
        removeEventListener(dom,'touchcancel',this.touchEnd);
    }
    destroy(){
        this.unbindMove();
        this.unbindEvents();
    }
}

export default DownRefresh;